package com.lfy.yunpicture.manager.filemanager;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lfy.yunpicture.common.ErrorCode;
import com.lfy.yunpicture.constant.FileConstant;
import com.lfy.yunpicture.exception.BusinessException;
import com.lfy.yunpicture.exception.ThrowUtils;
import com.lfy.yunpicture.manager.CosManager;
import com.lfy.yunpicture.mapper.FormatsMapper;
import com.lfy.yunpicture.model.dto.file.UploadPictureRequest;
import com.lfy.yunpicture.model.entity.Formats;
import com.lfy.yunpicture.model.enums.FileUploadBizEnum;
import com.lfy.yunpicture.model.vo.PictureMessageResponse;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.model.ciModel.persistence.CIObject;
import com.qcloud.cos.model.ciModel.persistence.ImageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
public class FileCommonManager {
    @Resource
    private CosManager cosManager;
    @Resource
    private FormatsMapper formatsMapper;
    private static final String COS_FOLDER_NAME = "yun_picture";
    private static final long ONE_M = 1024 * 1024 * 3L;
    private long SIZE;
    private String format;


    /**
     * 通用上传文件或URL
     *
     * @param obj
     * @param uploadPictureRequest
     * @param userId
     * @return
     */
    public PictureMessageResponse uploadFile(Object obj, UploadPictureRequest uploadPictureRequest, long userId) {
        String biz = uploadPictureRequest.getBiz();
        FileUploadBizEnum fileUploadBizEnum = FileUploadBizEnum.getEnumByValue(biz);
        if (fileUploadBizEnum == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        String filepath = null;
        if(obj instanceof MultipartFile){
            MultipartFile multipartFile = (MultipartFile) obj;
            // 文件校验
            validFile(multipartFile);
            // 自定义文件地址
            filepath = getFilepath(multipartFile.getOriginalFilename(), userId, fileUploadBizEnum);
        }else{
            String uploadUrl = (String) obj;
            validUrl(uploadUrl);
            // 取出路径参数前面的，避免出现错误
            int indexOf = uploadUrl.indexOf("?");
            if(indexOf != -1){
                uploadUrl = uploadUrl.substring(0,indexOf);
            }
            filepath = getFilepath(uploadUrl, userId, fileUploadBizEnum);
        }
        File file = null;
        PictureMessageResponse pictureMessageResponse = null;
        try {
            log.info("文件地址：{}",filepath);
            // 创建临时文件
            file = File.createTempFile(filepath, null);
            // 将文件写入临时文件
            if(obj instanceof MultipartFile){
                MultipartFile multipartFile = (MultipartFile) obj;
                multipartFile.transferTo(file);
                // 上传文件
                pictureMessageResponse = getPictureMessageResponse(multipartFile.getSize(), filepath, file);
            }else{
                String uploadUrl = (String) obj;
                // 将文件下载下来
                HttpUtil.downloadFile(uploadUrl, file);
                // 上传文件
                pictureMessageResponse = getPictureMessageResponse(SIZE,filepath, file);
            }
                return pictureMessageResponse;
        } catch (Exception e) {
            log.error("file upload error, filepath = " + filepath, e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "上传失败");
        } finally {
            if (file != null) {
                // 删除临时文件
                boolean delete = file.delete();
                if (!delete) {
                    log.error("file delete error, filepath = {}", filepath);
                }
            }
        }
    }
    private String getFilepath(String url, Long userId, FileUploadBizEnum fileUploadBizEnum) {
        // 文件目录：根据业务、用户来划分
        String uuid = RandomStringUtils.randomAlphanumeric(8);
        //发送文件的后缀
        String fileSuffix = FileUtil.getSuffix(url);
        if(format != null && !format.isEmpty()){
            fileSuffix = format;
        }
        String filename = uuid + "." + fileSuffix;
        //cos存储文件：项目名称+图片分类（user_avator/public/private...）+创建用户id+随机生成的8位字符串+文件后缀
        String filepath = String.format("/%s/%s/%s/%s", COS_FOLDER_NAME, fileUploadBizEnum.getValue(), userId, filename);
        return filepath;
    }

    /**
     * 获取图片信息
     * @param filepath
     * @param file
     * @return
     */
    @NotNull
    private PictureMessageResponse getPictureMessageResponse(Long size ,String filepath, File file) {
        PutObjectResult putObjectResult  = cosManager.putPictureObject(filepath, file);
        //根据putObjectResult获取图片基本信息
        ImageInfo imageInfo = putObjectResult.getCiUploadResult().getOriginalInfo().getImageInfo();
        List<CIObject> objectList = putObjectResult.getCiUploadResult().getProcessResults().getObjectList();
        CIObject ciObject = objectList.get(0);
        PictureMessageResponse pictureMessageResponse = new PictureMessageResponse();
        // 如果key不为空，则替换filepath
//        if(ciObject != null){
//            String key = ciObject.getKey();
//            if(StringUtils.isNotBlank(key)){
//                filepath = key;
//            }
//        }
        pictureMessageResponse.setUrl(FileConstant.COS_HOST + filepath);
        String thumbnail = null;
        if(objectList.size() > 1){
            ciObject = objectList.get(1);
            if(ciObject != null){
                thumbnail = ciObject.getKey();
            }
        }
        // 如果缩略图不为空
        if(StringUtils.isNotBlank(thumbnail)){
            pictureMessageResponse.setThumbnail(FileConstant.COS_HOST + thumbnail);
        }
        pictureMessageResponse.setName(FileUtil.mainName(filepath));
        pictureMessageResponse.setPicSize(size);
        pictureMessageResponse.setPicWidth(imageInfo.getWidth());
        pictureMessageResponse.setPicHeight(imageInfo.getHeight());
        double picScale = (double) imageInfo.getWidth() / (double) imageInfo.getHeight();
        pictureMessageResponse.setPicScale(picScale);
        pictureMessageResponse.setPicFormat(imageInfo.getFormat());
        // 返回可访问地址
        return pictureMessageResponse;
    }

    /**
     * 校验文件Url
     *
     * @param uploadUrl
     */
    private void validUrl(String uploadUrl) {
        // 校验URL是否存在
        ThrowUtils.throwIf(uploadUrl == null, ErrorCode.PARAMS_ERROR, "URL不能为空");
        // 校验Url格式是否正确
        try {
            new URL(uploadUrl);
        } catch (MalformedURLException e) {
            log.error("file upload error, url = " + uploadUrl, e);
            ThrowUtils.throwIf(true, ErrorCode.PARAMS_ERROR, "URL格式不正确");
        }
        // 校验Url协议
        ThrowUtils.throwIf(!uploadUrl.startsWith("http://") && !uploadUrl.startsWith("https://"), ErrorCode.PARAMS_ERROR, "URL协议错误");
        // 发送HEAD请求，查看文件是否存在
        HttpURLConnection connection = null;
        try {
            connection = (HttpURLConnection) new URL(uploadUrl).openConnection();
            connection.setRequestMethod("HEAD");
            connection.connect();
            int responseCode = connection.getResponseCode();
            // 如果不存在，直接return
            if (responseCode != HttpURLConnection.HTTP_OK) {
                log.error("file upload error, url = " + uploadUrl);
                return;
            }
            // 校验Content-Type是否为图片类型
            String contentType = connection.getContentType();
            ThrowUtils.throwIf(!contentType.startsWith("image"), ErrorCode.PARAMS_ERROR, "URL文件不是图片");
            format = contentType.substring(contentType.indexOf("/")+1);
            log.info("format: {}",format);
            // 获取Content-length校验文件大小
            int contentLength = connection.getContentLength();
            SIZE = contentLength;;
            ThrowUtils.throwIf(contentLength != -1 && contentLength > ONE_M, ErrorCode.PARAMS_ERROR, "URL文件大小不能超过 2M");
        } catch (IOException e) {
            log.error("file upload error,url = " + uploadUrl, e);
            ThrowUtils.throwIf(true, ErrorCode.PARAMS_ERROR, "URL文件不存在");
        }finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }
    /**
     * 校验文件
     *
     * @param multipartFile
     */
    private void validFile(MultipartFile multipartFile) {
        // 文件大小
        long fileSize = multipartFile.getSize();
        // 文件后缀
        String fileSuffix = FileUtil.getSuffix(multipartFile.getOriginalFilename());
        if (fileSize > ONE_M) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "图片大小不能超过 2M");
        }
        // 检查文件后缀是否存在
        List<Formats> formats = formatsMapper.selectList(new QueryWrapper<Formats>().select("format"));
        List<String> formatList = formats.stream()
                .map(Formats::getFormat)
                .collect(Collectors.toList());
        if (CollUtil.isNotEmpty(formats) && !formatList.contains(fileSuffix)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "图片类型错误,所需图片类型为jpeg，jpg，svg，png，webp");
        }
    }
}
